package com.request.service.impl.upstream;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.ejlchina.okhttps.HTTP;
import com.ejlchina.okhttps.OkHttps;
import com.request.common.constants.RedisConstant;
import com.request.config.thread.ServerConfigurer;
import com.request.entity.UpstreamCallBack;
import com.request.entity.UpstreamCallBackVO;
import com.request.service.RedisService;
import com.request.service.UpstreamCallBackService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * Description:
 * Create DateTime: 2020-04-02 18:01
 *
 * 

 */
@Slf4j
@Service
public class UpstreamCallBackServiceImpl implements UpstreamCallBackService {

    private static final Map<String, String> HEADER_MAP = new HashMap<>(2);

    static {
        HEADER_MAP.put("Content-Type", "application/json;charset=utf-8");
    }

    @Resource
    private ThreadPoolExecutor handlerOrderExecutor;

    @Resource
    private RedisService redisService;

    @Resource
    private ServerConfigurer serverConfigurer;

    @Resource
    private HTTP http;

    private ExecutorService service = Executors.newFixedThreadPool(3);

    @Override
    public void handlerUpstreamCallBack() {
        service.execute(() -> {
            //log.info("【渠道】【redis查询】操作开始:{}==========={}", DateUtil.dateToString(new Date(), "yyyy-MM-dd HH:mm:ss"));
            Long listSize = redisService.getListSize(RedisConstant.PUSH_ORDER_UP_STREAM_WAIT_CALL_BACK);
            //log.info("【渠道】【redis查询】操作结束:{}==========={}", DateUtil.dateToString(new Date(), "yyyy-MM-dd HH:mm:ss"));

            if (listSize == null || listSize == 0) {
                return;
            }

            if (listSize > serverConfigurer.getHandlerMaxSize()) {
                listSize = (long) serverConfigurer.getHandlerMaxSize();
            }
            //log.info("【渠道回调】操作开始:{}====个数{}", DateUtil.dateToString(new Date(), "yyyy-MM-dd HH:mm:ss"), listSize);

            for (int i = 0; i < listSize; i++) {
                Object object = redisService.rPop(RedisConstant.PUSH_ORDER_UP_STREAM_WAIT_CALL_BACK);
                if (null == object) {
                    return;
                }
                UpstreamCallBack upstreamCallBack = JSONObject.parseObject(object.toString(), UpstreamCallBack.class);
                handlerOrderExecutor.execute(() -> executeWaitOrderQuery(upstreamCallBack));
            }
            //log.info("【渠道回调】操作结束:{}", DateUtil.dateToString(new Date(), "yyyy-MM-dd HH:mm:ss"));
        });
    }

    /**
     * 执行回调渠道
     *
     * @param upstreamCallBack 待查询订单
     */
    private void executeWaitOrderQuery(UpstreamCallBack upstreamCallBack) {
        String url = upstreamCallBack.getUrl();
        Object data = upstreamCallBack.getData();
        Map<String, Object> params = new HashMap<>(2);
        params.put("data", data);

        JSONObject object = JSONObject.parseObject(data.toString());
        log.info("【回调渠道】参数为:{}", data.toString());

        String orderNo = object.getString("orderNo");
        String bizOrderNo = object.getString("bizOrderNo");

        http.async(url)
                .bodyType(OkHttps.JSON)
                .addBodyPara(params)
                .addHeader(HEADER_MAP)
                .setOnResponse(response -> {
                    try {
                        String dataStr = response.getBody().toString();
                        JSONObject result = JSON.parseObject(dataStr);
                        log.info("【回调渠道】订单号：{}, 返回结果:{}", bizOrderNo, result.toString());
                        if (!"1".equals(result.getString("code"))) {
                            throw new Exception("【回调渠道】响应接收失败，响应result为：" + result);
                        } else {
                            UpstreamCallBackVO upstreamCallBackVO = new UpstreamCallBackVO();
                            upstreamCallBackVO.setOrderNo(orderNo);
                            upstreamCallBackVO.setBizOrderNo(bizOrderNo);
                            saveUpstreamCallBackForSuccess(upstreamCallBackVO);
                        }
                    } catch (Exception e) {
                        log.error("【渠道回调】出现异常， 渠道订单号为:{}, 平台订单号为:{}, 详情为：", orderNo, bizOrderNo, e);
                        saveUpstreamCallBackForFailed(upstreamCallBack);
                    }
                })
                .setOnException(exception -> {
                    log.error("【渠道回调】okhttp响应异常， 渠道订单号为:{}, 平台订单号为:{}, 详情为：", orderNo, bizOrderNo, exception);
                    saveUpstreamCallBackForFailed(upstreamCallBack);
                }).post();
    }

    /**
     * 放入成功队列
     */
    private void saveUpstreamCallBackForSuccess(UpstreamCallBackVO upstreamCallBackVO) {
        redisService.lPush(RedisConstant.PUSH_ORDER_UP_STREAM_WAIT_CALL_BACK_SUCCESS, JSON.toJSONString(upstreamCallBackVO));
    }

    /**
     * 放入失败队列
     */
    private void saveUpstreamCallBackForFailed(UpstreamCallBack upstreamCallBack) {
        redisService.lPush(RedisConstant.PUSH_ORDER_UP_STREAM_WAIT_CALL_BACK_FAILED, JSON.toJSONString(upstreamCallBack));
    }
}
